#include "Bloque.h"
#include "funciones.h"

namespace Toolkit
{

Bloque::Bloque(const unsigned long int &tamanoBloque,
        const TipoSerializacion &tSerializacion, const bool &ordenado) :
    Componente(tSerializacion)
{
    this->tamanoBloque = tamanoBloque;
    this->ordenado = ordenado;
    espacioOcupado = 0;
}

Bloque::~Bloque()
{

}

void Bloque::serializacionFinalComponente(const Componente &componente,
        stringstream& s) const //TODO PROBAR: ALTAS PROBABILIDADES DE CHAPARRONES
{
    stringstream ssAux;
    componente.serializar(ssAux);

    if (this->tSerializacion == BINARIO)
    {
        s.write((const char *) ssAux.str().size(), sizeof(int));
        s.write(ssAux.str().c_str(), ssAux.str().size());
    }
    else if (this->tSerializacion == TEXTO)
    {
        s << intToStr(ssAux.str().size(), TAMANO_ID_TEXTO);
        s << ssAux;
    }
}

void Bloque::serializar(stringstream& s) const
{

    for (list<Componente*>::const_iterator it = componentes.begin(); it
            != componentes.end(); it++)
    {
        stringstream ssAux;
        serializacionFinalComponente((**it), ssAux);
    }
}

void Bloque::hidratar(stringstream& s)
{

    //    for (list<Componente*>::const_iterator it = componentes.begin(); it
    //            != componentes.end(); it++)
    //    {
    //
    //        stringstream serializacion;
    //
    //        if (this->tSerializacion == BINARIO)
    //        {
    //s        .read(, sizeof(int));
    //
    //    }
    //    else if (this->tSerializacion == TEXTO)
    //    {
    //        stringstream serializacionTamano;
    //
    //        serializacionTamano << std::setw(TAMANO_ID_TEXTO)
    //        << ssAux.str().size();
    //
    //        s << serializacionTamano;
    //        s << ssAux;
    //    }
}

unsigned long int Bloque::espacioLibre() const
{
    return tamanoBloque - espacioOcupado - TAMANO_ID_TEXTO;
}

unsigned long int Bloque::getTamanoBloque() const
{
    return tamanoBloque;
}

bool Bloque::agregar(Componente &componente, const Clave & clave)
{
    stringstream s;
    serializacionFinalComponente(componente, s);

    int espacioComponente = s.str().size();

    if (espacioOcupado + espacioComponente > tamanoBloque)
    {
        return false; //TODO mejor con una excepcion. Analizar
    }
    else
    {
        list<Componente*>::iterator it = componentes.begin();
        if (ordenado)
        {
            while ((it != componentes.end()) && ((**it) < clave))
            {
                it++;
            }

            if ((**it) == clave)
            { //Si intento meter un componente con una clave duplicda, se debe lanzar una excepcion
                return false;//TODO mejor con una excepcion
            }
        }
        else
        {
            while (it != componentes.end())
            {
                if ((**it) == clave)
                { //Si intento meter un componente con una clave duplicda, se debe lanzar una excepcion
                    return false;
                }
                it++;
            }
        }
        componentes.insert(it, &componente); //En caso de que no haya habido ningun problema se inserta
        espacioOcupado += espacioComponente; //el componente y se actualiza el espacioOcupado
    }

    return true;
}

Componente* Bloque::remover(const Clave & clave)
{
    Componente* c = buscar(clave);
    if (c == NULL)
    {
        return NULL;
    }

    stringstream s;
    serializacionFinalComponente(*c, s);

    espacioOcupado -= s.str().size();
    componentes.remove(c);
    return c;

}

Componente* Bloque::buscar(const Clave & clave)
{
    list<Componente*>::iterator it = componentes.begin();
    while (it != componentes.end())
    {
        if (**it == clave)
        {
            return *it;
        }
        it++;
    }

    return NULL;
}

Componente* Bloque::pop()
{
    Componente *aux = componentes.back();
    componentes.pop_back();

    return aux;
}

bool Bloque::operator <(const Clave &clave) const
{
    return *componentes.back() < clave;
}

bool Bloque::operator ==(const Clave &clave) const
{
    return *componentes.back() == clave;
}

int Bloque::cantElementos() const
{
    return componentes.size();
}

char Bloque::getTipo() const
{
    return 'B';
}

}

